/*
  This is a container that keeps track of which items we own and which we need. 
  It has an inventory with unassigned items and a assigned for assigned items.
  There is one of these for each different item, it keeps track of all days.
  
  The client object also contains the items that are assigned to it.
*/
package jcn2000;
import java.util.Vector; 
import java.util.Iterator;
import java.io.*;

class AllocationContainer {

  protected int     type      = -1;          //What type this container is

  //environment
  protected int[]   inventory = new int[5];  //How much we own
  protected float[] price     = new float[5];//How much the market price is now
  protected int[]   bids      = new int[5];  //How much we have placed a bid on
  protected float[] bidPrice  = new float[5];//At what price we placed the bid
  protected int[]   hqw       = new int[5];  //How much we will probably get

  protected int[][]   assigned  = new int[2][5];  //How much we set aside for use
  protected float[]   spent   = new float[5]; //how much I spent on this auction
  
  protected int whatIfDay = -1;    
  protected int whatIf = 0;
//  protected int[]   savedBid  = new int[5];  //Place to save the bids
  
  protected regressionFunction[] linear      =  new regressionFunction[5];
  protected regressionFunction[] exponential =  new regressionFunction[5];
   
  /**************************************************
  Basic Functions erasing and so on.
  **************************************************/
  //init function
  public AllocationContainer(int type_param) {
    type = type_param;
    for(int day = 0;day<5;day++){
      linear[day] = new regressionFunction();
      exponential[day] = new regressionFunction();
    }
    clear();
  }
  

  //reset function
  public void clear() {
    for(int i = 0;i<5;i++){
      inventory[i] = 0;
      assigned[0][i] = 0;
      assigned[1][i] = 0;
      bids[i] = 0;
      price[i] = 0;
      bidPrice[i] = 0;
      hqw[i] = 0;
      linear[i].clear();
      exponential[i].clear();
      whatIf = 0;
      spent[i] = 0;
    }
  }
 
  //kindly request to set an item aside
  public void request(int day){
    assigned[whatIf][day]++;
  }
  
  public void clearAssignments(){
    for(int i = 0;i<5;i++){
      assigned[whatIf][i] = 0;
    }
  }
  
  //returns the amount of unassigned items in stock
  public int getInventory(int day){
    return inventory[day] + hqw[day] - assigned[whatIf][day];
  }

  //If I where to request an item, what would it cost me?
  //If I have it, or it looks like I'm going to then it'll cost me nothing
  //Else it'll cost me the price I think the market is going to be next cycle
  public float cost(int day){
  	if (getInventory(day)>0){
  		return 0.0f;
  	}
  	else {
    	return predictPrice(day, true);
  	}
  }
  
  public void whatIf(boolean start, int d){
    whatIf = start ? 1 : 0;
    whatIfDay = d;
  }
  
  public boolean whatIf(int d){
    return d == whatIfDay;
  }
  
  //request info about the bids we need to place
  public float[] getBidsToPlace(int day){
    float retVal[] =  new float[2];
    if (getInventory(day) >= 0){
      retVal[0]=0;
      return retVal;
    }
    if (type==JCN2000.CAT_HOTEL){
      retVal[0] = (bids[day] > assigned[whatIf][day])? bids[day] : assigned[whatIf][day];
    }
    else{
      retVal[0] = getInventory(day)*-1;
    }
    retVal[1] = predictPrice(day, false)+10;
    return retVal;
  }
  
  private float predictPrice(int day,boolean needAnswer){
    if (price[day] == 0){
      return 0;
    }
    if ((hqw[day] <= bids[day]) && (type==JCN2000.CAT_HOTEL)){
      return needAnswer ? (price[day]+50 > 80 ? price[day]+50 : 80 ): -1;
    }
    else {
      return price[day];
    }
  }
  
  public float getBidPrice(int day){
    return bidPrice[day];
  }
  
  public float getMarketPrice(int day){
    return price[day];
  }

  /*
   * **********************************************
   * Functions to update our knowledge of the world
   * **********************************************
   */
  public void updatePrice(int day, float newPrice, float time){
  	//the linear tracks the prices
  	linear[day].update(time, newPrice);
  	//exponential tracks the price differences
  	exponential[day].update(time,newPrice-price[day]);
  	price[day] = newPrice;
  }
  
  
  //A bid as been awarded for a quantity qty and we got an amount of recqty
  public void bidReceived(int day, int recqty, float price){
    //I only place one simultaneous bid, that I sometimes replace.
  	updateBid(day,0,0);
  	inventory[day] += recqty;
  	updateHQW(day,0);
  	spent[day] += price;
  }
  
  //notify of the change of a bid
  public void updateBid(int day, int qty, float newPrice){
  	bids[day] = qty;
  	bidPrice[day] = newPrice;
  	//fixme:hqw changes as well
  }

  public void updateHQW(int day, int newHQW){
    hqw[day] = (newHQW > 0) ? newHQW : 0;
  }
  
  /**************************************************************
   for debugging purposes, I sometimes simply want some variables,
   these should only be used there (I cast them to string to make
   sure they are not accidentily used in calculations)
   **************************************************************/
  public String dbgGetAssigned(int day){
    return ""+assigned[whatIf][day];
  }
  
  public String dbgGetInventory(int day){
    return ""+inventory[day];
  }

  public String dbgGetHQW(int day){
    return ""+(inventory[day]+hqw[day]);
  }

  public void dbgTstAllocationContainer(PrintStream xml){
    for (int d=0;d<5;d++){
      xml.print("  <day n=\""+d+"\" ");
      xml.print("type=\""+type+"\" ");
      xml.print("inventory=\""+inventory[d]+"\" ");
      xml.print("assigned=\""+assigned[0][d]+"\" ");
      xml.print("price=\""+price[d]+"\" ");
      xml.print("bids=\""+bids[d]+"\" ");
      xml.print("bidPrice=\""+bidPrice[d]+"\" ");
      xml.print("hqw=\""+hqw[d]+"\" ");
      xml.print("spent=\""+spent[d]+"\" ");
      xml.println("/>");
    }
  }
}
